/*
 * This file is part of connotea-java.
 *
 * connotea-java is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * connotea-java is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package org.connotea;

import static org.apache.commons.lang.StringUtils.isNotBlank;
import static org.apache.commons.logging.LogFactory.getLog;

import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.restlet.Client;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.Form;
import org.restlet.data.Method;
import org.restlet.data.Protocol;
import org.restlet.data.Request;
import org.w3c.dom.Document;

/**
 * {@link Connector} implementation built on <a
 * href="http://restlet.org">Restlet</a>.
 */
public class RestletConnector implements Connector {

    private static final int DEFAULT_TIMEOUT = 0;

    private static final Log LOG = getLog(RestletConnector.class);

    private Client client;

    private String username;

    private String password;

    /**
     * Default, no-argument constructor.
     */
    public RestletConnector() {
        this(null, null, DEFAULT_TIMEOUT);
    }

    /**
     * Instantiate with a username and password to use for HTTP Basic
     * authentication.
     * 
     * @param username the username
     * @param password the password
     */
    public RestletConnector(String username, String password) {
        this(username, password, DEFAULT_TIMEOUT);
    }

    /**
     * Instantiate with a username and password to use for HTTP Basic
     * authentication and a timeout in seconds.
     * 
     * @param username the username
     * @param password the password
     * @param timeout the timeout in seconds
     */
    public RestletConnector(String username, String password, int timeout) {
        client = new Client(Protocol.HTTP);
        client.setConnectTimeout(timeout * 1000);
        this.username = username;
        this.password = password;
    }

    /**
     * @see org.connotea.Connector#get(java.lang.String)
     */
    public Response get(String uri) {
        Request request = new Request(Method.GET, uri);
        request.setChallengeResponse(getChallengeResponse());
        org.restlet.data.Response r = client.handle(request);
        int status = r.getStatus().getCode();
        Document document = null;
        try {
            r.getEntityAsDom().getDocument();
        } catch (Exception e) {
            LOG.debug(e);
        }
        return new Response(status, document);
    }

    /**
     * @see org.connotea.Connector#post(java.lang.String, java.util.Map)
     */
    public Response post(String uri, Map<String, String> parameters) {
        Form form = new Form();
        for (Entry<String, String> parameter : parameters.entrySet()) {
            form.add(parameter.getKey(), parameter.getValue());
        }
        try {
            form.encode();
        } catch (Exception e) {
            throw new ConnoteaRuntimeException("could not encode form: " + form);
        }
        Request request = new Request(Method.POST, uri);
        request.setEntity(form.getWebRepresentation());
        request.setChallengeResponse(getChallengeResponse());
        org.restlet.data.Response r = client.handle(request);
        int status = r.getStatus().getCode();
        Document document = null;
        try {
            document = r.getEntityAsDom().getDocument();
        } catch (Exception e) {
            LOG.debug(e);
        }
        return new Response(status, document);
    }

    private ChallengeResponse getChallengeResponse() {
        if (isNotBlank(username) && isNotBlank(password)) {
            return new ChallengeResponse(ChallengeScheme.HTTP_BASIC, username,
                    password);
        }
        return null;
    }
}
